package com.sf.shiva.oms.common.util;


import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import com.sf.shiva.oms.common.exception.OmsRuntimeException;

/**
 * 
 * 描述：注解工具类
 * 
 * <pre>
 * HISTORY
 * ****************************************************************************
 *  ID   DATE            PERSON            REASON
 *  1    2016年6月25日    866321            Create
 * ****************************************************************************
 * </pre>
 * 
 * @author 866321
 * @param <T>
 */
public final class AnnotationUtil {

    private AnnotationUtil() {
    }

    /**
     * 得到指定注解的类的属性
     * 
     * @param clazz
     *            实体类Class
     * @param annotationClass
     *            注解Class
     * @return 属性集合
     */
    public static <T extends Annotation> List<Field> getFields(Class<?> clazz, Class<T> annotationClass) {
        List<Field> result = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            T t = field.getAnnotation(annotationClass);
            if (null != t) {
                result.add(field);
            }
        }
        Class<?> superClass = clazz.getSuperclass();
        if (null != superClass) {
            List<Field> superFields = getFields(superClass, annotationClass);
            for (Field field : superFields) {
                result.add(field);
            }
        }
        return result;
    }

    /**
     * 根据类Class和注解Class获取此类属性中所有的指定注解
     * 
     * @param clazz
     *            类Class
     * @param annotationClass
     *            注解Class
     * @return 此类属性中所有的指定注解
     */
    public static <A extends Annotation> List<A> getFieldAnnotations(Class<?> clazz, Class<A> annotationClass) {
        List<A> annotations = new ArrayList<A>();
        List<Field> fields = getFields(clazz, annotationClass);
        for (Field field : fields) {
            A annotation = field.getAnnotation(annotationClass);
            annotations.add(annotation);
        }
        return annotations;
    }

    /**
     * 根据类Class、属性名和注解Class获取此属性的注解
     * 
     * @param clazz
     *            类Class
     * @param fieldName
     *            属性名
     * @param annotationClass
     *            注解Class
     * @return 此属性的注解
     */
    public static <A extends Annotation> A getFieldAnnotation(Class<?> clazz, String fieldName,
            Class<A> annotationClass) {
        List<Field> fields = getFields(clazz, annotationClass);
        for (Field field : fields) {
            if (fieldName.equals(field.getName())) {
                return field.getAnnotation(annotationClass);
            }
        }
        return null;
    }

    /**
     * 获取指定类的指定注解的属性名称
     * 
     * @param clazz
     *            指定类
     * @param annotationClass
     *            指定注解
     * @return 属性名称
     */
    public static <A extends Annotation> List<String> getFieldName(Class<?> clazz, Class<A> annoClass) {
        List<String> result = new ArrayList<>();
        List<Field> fields = getFields(clazz, annoClass);
        for (Field field : fields) {
            result.add(field.getName());
        }
        return result;
    }

    /**
     * 获取指定业务数据的指定注解的属性值
     * 
     * @param bean
     *            指定业务数据
     * @param annoClass
     *            指定注解
     * @return 属性值
     */
    public static <B, A extends Annotation> List<String> getFieldValue(B bean, Class<A> annoClass) {
        try {
            List<String> fieldValues = new ArrayList<String>();
            @SuppressWarnings("unchecked")
            Class<B> clazz = (Class<B>) bean.getClass();
            List<String> fieldNames = getFieldName(clazz, annoClass);
            for (String fieldName : fieldNames) {
                String getMethodName = "get".concat(fieldName.substring(0, 1).toUpperCase())
                        .concat(fieldName.substring(1));
                Method getMethod = bean.getClass().getMethod(getMethodName);
                Object object = getMethod.invoke(bean);
                if (object instanceof Long) {
                    fieldValues.add((Long) object + "");
                } else if (object instanceof Integer) {
                    fieldValues.add((Integer) object + "");
                } else if (object instanceof String) {
                    fieldValues.add((String) object);
                } else {
                    String msg = String.format("This type[%s] is not supported.", getMethod.getReturnType().getName());
                    throw new OmsRuntimeException(msg);
                }
            }
            return fieldValues;
        } catch (Exception e) {
            throw new OmsRuntimeException(e);
        }
    }
    
    /**
     * 根据类Class、属性名和注解Class获取此属性的注解
     * 
     * @param clazz
     *            类Class
     * @param fieldName
     *            属性名
     * @param annotationClass
     *            注解Class
     * @return 此属性的注解
     */
    public static <A extends Annotation> A getMethodAnnotation(Class<?> clazz, String methodName, Class<A> annotationClass) {
        List<Method> methods = getMethods(clazz, annotationClass);
        Method annoMethod= methods.stream().filter(method -> methodName.equals(method.getName())).findFirst().orElse(null);
        if (annoMethod!=null){
            return annoMethod.getAnnotation(annotationClass);
        }
        return null;
    }
    /**
     * 得到指定注解的类的方法
     * 
     * @param clazz
     *            实体类Class
     * @param annotationClass
     *            注解Class
     * @return 属性集合
     */
    public static <T extends Annotation> List<Method> getMethods(Class<?> clazz, Class<T> annotationClass) {
        List<Method> result = new ArrayList<>();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            T t = method.getAnnotation(annotationClass);
            if (null != t) {
                result.add(method);
            }
        }
        return result;
    }
}
